<template>
  <div id="app">
    <div class="container">
      <!-- 创建一个canvas画布 npmn-js是通过canvas实现绘图的，并设置ref让vue获取到element -->
      <div class="bpmn-container">
        <div class="bpmn-canvas" ref="canvas"></div>
        <!-- 工具栏显示的地方 -->
        <div class="bpmn-js-properties-panel" id="js-properties-panel"></div>
      </div>

      <!-- 把操作按钮写在这里面 -->
      <div class="action">
        <el-upload action class="upload-demo" :before-upload="openBpmn">
          <el-button>文件</el-button>
        </el-upload>
        <el-button class="new" @click="newDiagram">初始化</el-button>
        <el-button @click="downloadBpmn">文件下载</el-button>
        <el-button @click="downloadSvg">svg下载</el-button>
        <a hidden ref="downloadLink"></a>
      </div>
    </div>
  </div>
</template>

<script>
import BpmnModeler from 'bpmn-js/lib/Modeler'
// 工具栏相关
import propertiesProviderModule from 'bpmn-js-properties-panel/lib/provider/camunda'
import propertiesPanelModule from 'bpmn-js-properties-panel'
import camundaModdleDescriptor from 'camunda-bpmn-moddle/resources/camunda'
// 汉化
import customTranslate from './customTranslate'

export default {
  data() {
    return {
      bpmnModeler: null,
      canvas: null,
      bpmnTemplate: `
          <?xml version="1.0" encoding="UTF-8"?>
          <definitions 
              xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" 
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
              xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" 
              xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" 
              xmlns:camunda="http://camunda.org/schema/1.0/bpmn" 
              xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
              xmlns:activiti="http://activiti.org/bpmn" 
              id="m1577635100724" 
              name="" 
              targetNamespace="http://www.activiti.org/testm1577635100724"
            >
            <process id="process" processType="None" isClosed="false" isExecutable="true">
              <extensionElements>
                <camunda:properties>
                  <camunda:property name="a" id='_1' value="1" />
                </camunda:properties>
              </extensionElements>
              <startEvent id="_2" />
            </process>
            <bpmndi:BPMNDiagram id="BPMNDiagram_leave">
              <bpmndi:BPMNPlane id="BPMNPlane_leave" bpmnElement="leave">
                <bpmndi:BPMNShape id="BPMNShape__2" bpmnElement="_2">
                  <omgdc:Bounds x="144" y="368" width="32" height="32" />
                  <bpmndi:BPMNLabel>
                    <omgdc:Bounds x="149" y="400" width="23" height="14" />
                  </bpmndi:BPMNLabel>
                </bpmndi:BPMNShape>
              </bpmndi:BPMNPlane>
            </bpmndi:BPMNDiagram>
          </definitions>
      `,
    }
  },
  methods: {
    newDiagram() {
      this.createNewDiagram(this.bpmnTemplate)
    },
    // 保存的时候camunda转activiti 跳过第一个
    formXML(data) {
      let count = 0
      let temp = data.replace(/camunda/gi, function (match) {
        count++
        if (count == 1) {
          return match
        } else {
          return 'activiti'
        }
      })
      temp = temp.replace(/FormField/gi, 'formProperty')
      return temp
    },

    // 回显的时候activiti转camunda
    reformXML(data) {
      let temp = data.replace(/activiti/gi, 'camunda')
      temp = temp.replace(/formProperty/gi, 'FormField')
      return temp
    },
    downloadBpmn() {
      this.bpmnModeler.saveXML({ format: true }, (err, xml) => {
        if (!err) {
          // 获取文件名
          const name = `${this.getFilename(xml)}.bpmn`
          // 将文件名以及数据交给下载方法
          this.download({ name: name, data: this.formXML(xml) })
        }
      })
    },
    downloadSvg() {
      this.bpmnModeler.saveXML({ format: true }, (err, xml) => {
        if (!err) {
          // 获取文件名
          const name = `${this.getFilename(xml)}.svg`

          // 从建模器画布中提取svg图形标签
          let context = ''
          const djsGroupAll = this.$refs.canvas.querySelectorAll('.djs-group')
          for (let item of djsGroupAll) {
            context += item.innerHTML
          }
          // 获取svg的基本数据，长宽高
          const viewport = this.$refs.canvas
            .querySelector('.viewport')
            .getBBox()

          // 将标签和数据拼接成一个完整正常的svg图形
          const svg = `
            <svg
              xmlns="http://www.w3.org/2000/svg"
              xmlns:xlink="http://www.w3.org/1999/xlink"
              width="${viewport.width}"
              height="${viewport.height}"
              viewBox="${viewport.x} ${viewport.y} ${viewport.width} ${viewport.height}"
              version="1.1"
              >
              ${context}
            </svg>
          `
          // 将文件名以及数据交给下载方法
          this.download({ name: name, data: this.formXML(svg) })
        }
      })
    },

    openBpmn(file) {
      const reader = new FileReader()
      // 读取File对象中的文本信息，编码格式为UTF-8
      reader.readAsText(file, 'utf-8')
      reader.onload = () => {
        //读取完毕后将文本信息导入到Bpmn建模器
        this.createNewDiagram(this.reformXML(reader.result))
      }
      return false
    },

    getFilename(xml) {
      let start = xml.indexOf('process')
      let filename = xml.substr(start, xml.indexOf('>'))
      filename = filename.substr(filename.indexOf('id') + 4)
      filename = filename.substr(0, filename.indexOf('"'))
      return filename
    },

    download({ name = 'diagram.bpmn', data }) {
      // 这里就获取到了之前设置的隐藏链接
      const downloadLink = this.$refs.downloadLink
      // 把数据转换为URI，下载要用到的
      const encodedData = encodeURIComponent(data)

      if (data) {
        // 将数据给到链接
        downloadLink.href =
          'data:application/bpmn20-xml;charset=UTF-8,' + encodedData
        // 设置文件名
        downloadLink.download = name
        // 触发点击事件开始下载
        downloadLink.click()
      }
    },

    async init() {
      // 获取画布 element
      this.canvas = this.$refs.canvas

      // 将汉化包装成一个模块
      const customTranslateModule = {
        translate: ['value', customTranslate],
      }

      // 创建Bpmn对象
      this.bpmnModeler = new BpmnModeler({
        // 设置bpmn的绘图容器为上门获取的画布 element
        container: this.canvas,

        // 加入工具栏支持
        propertiesPanel: {
          parent: '#js-properties-panel',
        },
        additionalModules: [
          // 工具栏模块
          propertiesProviderModule,
          propertiesPanelModule,
          // 汉化模块
          customTranslateModule,
        ],
        moddleExtensions: {
          camunda: camundaModdleDescriptor,
        },
      })

      await this.createNewDiagram(this.bpmnTemplate)
    },
    async createNewDiagram(bpmn) {
      // 将字符串转换成图显示出来;
      this.bpmnModeler.importXML(bpmn, (err) => {
        if (err) {
          this.$Message.error('打开模型出错,请确认该模型符合Bpmn2.0规范')
        }
      })
    },
  },
  mounted() {
    this.init()
  },
}
</script>

<style>
.bpmn-container {
  width: 100%;
  height: 100vh;
  display: flex;
}

.bpmn-canvas {
  width: calc(100% - 300px);
  height: 100vh;
}

.bpmn-js-properties-panel {
  width: 320px;
  height: inherit;
  overflow-y: auto;
}

.action {
  position: absolute;
  bottom: 120px;
  left: 10px;
  display: flex;
}
.upload-demo {
  margin-right: 10px;
}
</style>
